﻿@using WebApiClientCore
@implements IAsyncDisposable
@inject ITokenInterceptor Interceptor
@inject NavigationManager Navigation
@inject ToastService Toast
@inject AuthenticationStateProvider StateProvider

<CascadingValue Value="@this" IsFixed="true">
    <CascadingValue Value="@Context">
        @if (Initialized)
        {
            @ChildContent         
        }
    </CascadingValue>
</CascadingValue>

@code{
    /// <summary>
    /// 获得/设置 子组件内容
    /// </summary>
    [Parameter] 
    public RenderFragment? ChildContent { get; set; }

    /// <summary>
    /// 获得/设置 是否初始化完成
    /// </summary>
    private bool Initialized { get; set; }

    /// <summary>
    /// 获得/设置 Token上下文对象
    /// </summary>
    private TokenContext? Context { get; set; }

    /// <summary>
    /// SignalR连接
    /// </summary>
    private HubConnection? ChatHub { get; set; }

    /// <summary>
    /// OnInitialized
    /// </summary>
    protected override void OnInitialized()
    {
        Context = new(Interceptor);
        Context.Interceptor.BeforeSend += OnBeforeSend;
        Context.Interceptor.AfterSend += OnAfterSend;
        Context.UpdateClientToken += OnUpdateClientToken;
    }

    /// <summary>
    /// OnAfterRenderAsync
    /// </summary>
    /// <param name="firstRender"></param>
    /// <returns></returns>
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            //第一次渲染只是建立连接，读取客户端LocalStorage
            Context?.LoadToken(await StateProvider.GetAuthenticationStateAsync());

            //通过该参数强制刷新后重新渲染
            Initialized = true;

            StateHasChanged();
        }
        else
        {
            await HubConnectAsync();
        }
    }

    /// <summary>
    /// 建立SignalR连接
    /// </summary>
    private async Task HubConnectAsync()
    {
        if (ChatHub == null || ChatHub.State == HubConnectionState.Disconnected)
        {
            if (Context!.IsAuthenticated)
            {
                //admin.net这里使用url传access_token
                var query = $"?access_token={Context.AccessToken}";
                var builder = new UriBuilder(Navigation.ToAbsoluteUri("/hubs/chathub")) { Query = query };
                ChatHub = new HubConnectionBuilder()
                    .WithUrl(builder.Uri)
                    .Build();

                //接收消息
                ChatHub.On<object>("ReceiveMessage", (message) => { });

                //强制退出
                ChatHub.On("ForceExist", () => Context?.UpdateToken(false, null, null));

                await ChatHub.StartAsync();
            }
        }
    }

    /// <summary>
    /// 请求执行之前
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    private void OnBeforeSend(object? sender, ApiRequestContext? context)
    {
        if (context == null)
        {
            return;
        }

        var authorization = context.HttpContext.RequestMessage.Headers.Authorization;
        if (authorization != null && authorization.Scheme == "Bearer")
        {
            return;
        }

        if (string.IsNullOrWhiteSpace(Context?.AccessToken))
        {
            return;
        }

        context.HttpContext.RequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Context.AccessToken);
        if (string.IsNullOrWhiteSpace(Context?.RefreshToken))
        {
            return;
        }

        if (Context.IsExpiringSoon)
        {
            context.HttpContext.RequestMessage.Headers.TryAddWithoutValidation("X-Authorization", $"Bearer {Context.RefreshToken}");
        }
    }

    /// <summary>
    /// 请求执行后
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    /// <returns></returns>
    private void OnAfterSend(object? sender, ApiResponseContext? context)
    {
        //每次请求后需要检查一下响应头部
        //看是否生成了新的token
        if (context == null)
        {
            return;
        }

        //此处需要对接口返回的异常code和状态码进行处理，并进行对应提示，后续补充完善
        //Toast

        if (context.HttpContext.ResponseMessage == null)
        {
            return;
        }


        if (context.HttpContext.ResponseMessage.Headers.Contains("access-token") != true)
        {
            return;
        }

        var accessToken = context.HttpContext.ResponseMessage.Headers.GetValues("access-token").FirstOrDefault();
        if (accessToken == "invalid_token")
        {
            //异常Token，注销后重新登录
            Context?.UpdateToken(false, null, null);
        }

        if (context.HttpContext.ResponseMessage.Headers.Contains("x-access-token") != true)
        {
            return;
        }

        var refreshToken = context.HttpContext.ResponseMessage.Headers.GetValues("x-access-token").FirstOrDefault();
        if (string.IsNullOrWhiteSpace(accessToken) || string.IsNullOrWhiteSpace(refreshToken))
        {
            return;
        }

        //获取到新的Token
        Context?.UpdateToken(true, accessToken, refreshToken);
    }

    /// <summary>
    /// 更新或清除客户端Token信息
    /// <para>如果token认证有效会更新客户端LocalStorage里存储的token</para>
    /// <para>如果无效（包括过时）会清除客户端LocalStorage里存储的token</para>
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    /// <returns>void</returns>
    private async void OnUpdateClientToken(object? sender, (string?,string?) args)
    {
        await ((JwtAuthenticationStateProvider)StateProvider).UpdateAuthenticated(args.Item1, args.Item2);
    }

    /// <summary>
    /// DisposeAsync
    /// </summary>
    /// <returns></returns>
    public async ValueTask DisposeAsync()
    {
        if (Context != null)
        {
            Context.Interceptor.BeforeSend -= OnBeforeSend;
            Context.Interceptor.AfterSend -= OnAfterSend;
            Context.UpdateClientToken -= OnUpdateClientToken;
        }

        if (ChatHub != null)
        {
            await ChatHub.DisposeAsync();
        }
    }
}